package demo.log.logback;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import com.ximalaya.xdcs.client.logimpl.LogEventDes;
import org.apache.commons.lang.StringUtils;
import demo.log.model.GenericLogEvent;
import ch.qos.logback.classic.spi.ILoggingEvent;

public class LogbackEventAdapter implements GenericLogEvent {

    private final ILoggingEvent event;

    public LogbackEventAdapter(ILoggingEvent event) {
        this.event = event;
    }

    @Override
    public LogEventDes parseLogEvent() {
        if (event == null) {
            return null;
        }

        Level logLevel = Level.toLevel(null, Level.ERROR);
        if (event.getLevel().toInt() < logLevel.toInt()) {
            return null;
        }

        try {
            LogEventDes logEventDes = new LogEventDes();
            logEventDes.setLogLevelDes(event.getLevel().toString());
            logEventDes.setLogDetail(String.valueOf(event.getFormattedMessage()));
            logEventDes.setThreadName(event.getThreadName());
            logEventDes.setLogName(event.getLoggerName());
            logEventDes.setMessage(event.getFormattedMessage());

            if (Level.ERROR.equals(event.getLevel())) {

                IThrowableProxy errorInfo = event.getThrowableProxy();

                if (errorInfo != null) {
                    // 获得抛出异常的方法名称
                    StackTraceElementProxy[] stackTrace = event.getThrowableProxy().getStackTraceElementProxyArray();
                    if (stackTrace == null || stackTrace.length == 0) {
                        logEventDes.setMethodName("unknown");
                    } else {
                        logEventDes.setLogDetail(convertStackTrack(stackTrace, errorInfo.getMessage()));
                        StackTraceElementProxy lastElem = stackTrace[0]; // ArrayOutOfBoundException
                        logEventDes.setMethodName(lastElem.getStackTraceElement().getClassName() + ":" + lastElem.getStackTraceElement().getMethodName());
                        logEventDes.setLogIdentity(lastElem.getStackTraceElement().getClassName() + ":" + lastElem.getStackTraceElement().getMethodName() + ":" + lastElem.getStackTraceElement().getLineNumber());
                    }

                }
            }

            if (StringUtils.isBlank(logEventDes.getLogIdentity())) {
                StackTraceElement[] stackTraceElements = event.getCallerData();
                if (stackTraceElements != null && stackTraceElements.length > 0) {
                    StackTraceElement stackTraceElement = stackTraceElements[0];

                    StringBuilder sBuilder = new StringBuilder(stackTraceElement.getClassName());
                    String methodName = stackTraceElement.getMethodName();
                    String className = stackTraceElement.getClassName();
                    sBuilder.append(":");
                    sBuilder.append(methodName);
                    sBuilder.append(":");
                    sBuilder.append(stackTraceElement.getLineNumber());
                    logEventDes.setLogIdentity(sBuilder.toString());
                    logEventDes.setMethodName(className + ":" + methodName);
                } else {
                    logEventDes.setLogIdentity("unkown");
                    logEventDes.setMethodName("unkown");
                }
            }
            return logEventDes;
        } catch (Throwable ex) {
            System.err.println("doParseLogEvent failed:" + ex.getMessage());
        }
        return null;
    }

    private static String convertStackTrack(StackTraceElementProxy[] stackTraceElementProxies, String rootMessage) {
        StringBuilder stringBuilder = new StringBuilder();

        if (rootMessage != null && !"".equals(rootMessage)) {
            //root message 根因消息
            stringBuilder.append(rootMessage).append("\n\t");
        }

        for (StackTraceElementProxy stackTraceElementProxy : stackTraceElementProxies) {
            stringBuilder.append(stackTraceElementProxy.getSTEAsString()).append("\n\t");
        }

        return stringBuilder.toString();
    }
}
